// $Id: proto.pas 62 2006-07-27 16:54:30Z alpov $

unit proto;

interface

type
  PACKET_HEADER = packed record
    seq: Byte;
    dest: Byte;
    src: Byte;
    cmd: Byte;
    item_hi: Byte;
    item_lo: Byte;
  end;

  PACKET_FOOTER = packed record
    crc: Word;
  end;

const
  ADDR_SERVER            = 0;
  ADDR_TERMINAL          = 3;
  ADDR_PC                = $99;
  ADDR_BROADCAST         = $FF;
  CMD_ACKNOWLEDGE = 10;

procedure SerialSendAck(ph: PACKET_HEADER);
procedure SerialSendPacket(ph: PACKET_HEADER; data: Pointer; len: Byte);

implementation

uses Serial;

procedure ByteCrc(data:byte;var crc:word);
VAR i:BYTE;
BEGIN
 FOR i:=0 TO 7 DO
  BEGIN
   IF ((data and $01)XOR(crc AND $0001)<>0) THEN
    BEGIN
     crc:=crc shr 1;
     crc:= crc XOR $A001;
    END
   ELSE crc:=crc shr 1;
   data:=data shr 1; // this line is not ELSE and executed anyway.
  END;
END;

procedure SerialSendAck(ph: PACKET_HEADER);
var
  ph_ack: PACKET_HEADER;
begin
  ph_ack.seq := ph.seq;
  ph_ack.dest := ph.src;
  ph_ack.src := ADDR_PC;
  ph_ack.cmd := CMD_ACKNOWLEDGE;
  ph_ack.item_hi := 0;
  ph_ack.item_lo := 0;
  SerialSendPacket(ph_ack, nil, 0);
end;

procedure SerialSendPacket(ph: PACKET_HEADER; data: Pointer; len: Byte);
var
  head: array[0..2] of Byte;
  pf: PACKET_FOOTER;
  I: Integer;
  P: PChar;
begin
  pf.crc := $FFFF;
  head[0] := $AA;
  head[1] := $AA;
  head[2] := sizeof(PACKET_HEADER) + len;
  WriteCom(head, sizeof(head));
  P := @ph;
  for I := 0 to sizeof(PACKET_HEADER) - 1 do begin
    ByteCrc(Byte(P^), pf.crc);
    Inc(P);
  end;
  WriteCom(ph, sizeof(ph));
  P := data;
  for I := 0 to len - 1 do begin
    ByteCrc(Byte(P^), pf.crc);
    Inc(P);
  end;
  WriteCom(data^, len);
  WriteCom(pf, sizeof(pf));
end;

end.
